package bbs.aspect;

import bbs.annotation.GlobalInterceptor;
import bbs.annotation.VerifyParam;
import bbs.entity.config.WebConfig;
import bbs.entity.constants.Constants;
import bbs.entity.dto.SessionWebUserDto;
import bbs.entity.dto.SysSettingDto;
import bbs.entity.enums.DateTimePatternEnum;
import bbs.entity.enums.ResponseCodeEnum;
import bbs.entity.enums.UserOperFrequencyTypeEnum;
import bbs.entity.po.UserInfo;
import bbs.entity.query.ForumArticleQuery;
import bbs.entity.query.ForumCommentQuery;
import bbs.entity.query.LikeRecordQuery;
import bbs.entity.query.UserInfoQuery;
import bbs.entity.vo.ResponseVO;
import bbs.exception.BusinessException;
import bbs.service.ForumArticleService;
import bbs.service.ForumCommentService;
import bbs.service.LikeRecordService;
import bbs.service.UserInfoService;
import bbs.utils.DateUtil;
import bbs.utils.StringTools;
import bbs.utils.SysCacheUtils;
import bbs.utils.VerifyUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Date;
import java.util.List;


@Aspect
@Component
public class OperationAspect {
    private static Logger logger = LoggerFactory.getLogger(OperationAspect.class);

    private static final String[] TYPE_BASE = {"java.lang.String","java.lang.Integer","java.lang.Long"};

    @Pointcut("@annotation(bbs.annotation.GlobalInterceptor)")
    private void requestInterceptor() {}

    @Before("requestInterceptor()")
    public void interceptorDo(JoinPoint point) {
        try {
            Object target = point.getTarget();
            Object[] arrayOfObject = point.getArgs();
            String methodName = point.getSignature().getName();
            Class<?>[] arrayOfClass = ((MethodSignature)point.getSignature()).getMethod().getParameterTypes();
            Method method = target.getClass().getMethod(methodName, arrayOfClass);
            GlobalInterceptor globalInterceptor = method.<GlobalInterceptor>getAnnotation(GlobalInterceptor.class);
            if (null == globalInterceptor) return;

//            校验参数
            if (globalInterceptor.checkParams()) validateParams(method, arrayOfObject);

        } catch (BusinessException buisnessException) {
            logger.error("全局拦截器异常", (Throwable)buisnessException);
            throw buisnessException;
        } catch (Exception exception) {
            logger.error("全局拦截器异常", exception);
            throw new BusinessException(ResponseCodeEnum.CODE_500);
        } catch (Throwable throwable) {
            logger.error("全局拦截器异常", throwable);
            throw new BusinessException(ResponseCodeEnum.CODE_500);
        }
    }

    private void validateParams(Method paramMethod, Object[] paramArrayOfObject) throws BusinessException {
        Parameter[] arrayOfParameter = paramMethod.getParameters();
        for (byte b = 0; b < arrayOfParameter.length; b++) {
            Parameter parameter = arrayOfParameter[b];
            Object object = paramArrayOfObject[b];
            VerifyParam verifyParam = parameter.<VerifyParam>getAnnotation(VerifyParam.class);
            if (verifyParam != null)
                if (ArrayUtils.contains(TYPE_BASE, parameter.getParameterizedType().getTypeName())) {
                    checkValue(object, verifyParam);
                } else {
                    checkValue(parameter, verifyParam);
                }
        }
    }

    private void checkObjValue(Parameter paramParameter, Object paramObject) {
        try {
            String str = paramParameter.getParameterizedType().getTypeName();
            Class<?> clazz = Class.forName(str);
            Field[] arrayOfField = clazz.getDeclaredFields();
            for (Field field : arrayOfField) {
                VerifyParam verifyParam = field.<VerifyParam>getAnnotation(VerifyParam.class);
                if (verifyParam != null) {
                    field.setAccessible(true);
                    Object object = field.get(paramObject);
                    checkValue(object, verifyParam);
                }
            }
        } catch (BusinessException buisnessException) {
            logger.error("参数校验失败", (Throwable)buisnessException);
            throw buisnessException;
        } catch (Exception exception) {
            logger.error("参数校验失败", exception);
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
    }

    private void checkValue(Object paramObject, VerifyParam paramVerifyParam) throws BusinessException {
        Boolean bool = Boolean.valueOf((paramObject == null || StringTools.isEmpty(paramObject.toString())));
        Integer integer = Integer.valueOf((paramObject == null) ? 0 : paramObject.toString().length());
//        空值校验
        if (bool.booleanValue() && paramVerifyParam.required())
            throw new BusinessException(ResponseCodeEnum.CODE_600);
//        长度校验
        if (!bool.booleanValue() && ((paramVerifyParam.max() != -1 && paramVerifyParam.max() < integer.intValue()) || (paramVerifyParam.min() != -1 && paramVerifyParam.min() > integer.intValue())))
            throw new BusinessException(ResponseCodeEnum.CODE_600);
//        正则校验
        if (!bool.booleanValue() && !StringTools.isEmpty(paramVerifyParam.regex().getRegex()) && !VerifyUtils.verify(paramVerifyParam.regex(), String.valueOf(paramObject)))
            throw new BusinessException(ResponseCodeEnum.CODE_600);
    }
}
